// Promise的三种状态
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
  // 接收一个执行器
  constructor(executor) {
    try {
      executor(this.resolve, this.reject)
    } catch (err) {
      this.reject(err)
    }

  }
  // 状态
  status = PENDING
  // 存储成功值
  value = undefined
  // 存储失败原因
  error = undefined
  // 成功回调数组
  successCallbacks = []
  // 失败回调数组
  errorCallbacks = []
  resolve = (value) => {
    // 状态不是PENDING的话阻止向下运行
    if (this.status !== PENDING) return
    this.status = FULFILLED
    // 存储成功值
    this.value = value
    // 执行成功回调
    while (this.successCallbacks.length) {
      this.successCallbacks.shift()(this.value)
    }
  }

  // 和resolve基本一致
  reject = (error) => {
    if (status !== PENDING) return
    this.status = REJECTED
    this.error = error
    while (this.errorCallbacks.length) {
      this.errorCallbacks.shift()(this.value)
    }
  }

  then(successCallback, errorCallback) {
    successCallback = successCallback ? successCallback : value => value
    errorCallback = errorCallback ? errorCallback : error => {
      throw error
    }
    // 返回promise对象 以便链式调用
    let nextPromise = new MyPromise((resolve, reject) => {
      // 如果状态已经是成功
      if (this.status === FULFILLED) {
        // 异步 以便resolvePromise中可以取到nextPromise对象
        setTimeout(() => {
          try {
            let x = successCallback(this.value)
            // 判断x的类型 如果不是Promise对象 直接resolve
            // 如果是Promise对象则调用then方法
            resolvePromise(x, nextPromise, resolve, reject)
          } catch (err) {
            reject(err)
          }
        }, 0)
      } else if (this.status === REJECTED) {
        // 同理
        setTimeout(() => {
          try {
            let x = errorCallback(this.error)
            resolvePromise(x, nextPromise, resolve, reject)
          } catch (err) {
            reject(err)
          }
        }, 0)
      } else {
        // PENDING
        this.successCallbacks.push(() => {
          setTimeout(() => {
            try {
              let x = successCallback(this.value)
              // 判断x的类型 如果不是Promise对象 直接resolve
              // 如果是Promise对象则调用then方法
              resolvePromise(x, nextPromise, resolve, reject)
            } catch (err) {
              reject(err)
            }
          }, 0)
        })
        this.errorCallbacks.push(() => {
          setTimeout(() => {
            try {
              let x = errorCallback(this.error)
              resolvePromise(x, nextPromise, resolve, reject)
            } catch (err) {
              reject(err)
            }
          }, 0)
        })
      }
    })
    return nextPromise
  }
  // 无论成功失败都会执行
  // 如果返回一个promise 则等待finally返回的promise的对象执行完成后再继续执行
  finally(callback) {
    return this.then(
      value => MyPromise.resolve(callback()).then(() => value),
      error => MyPromise.resolve(callback()).then(() => {
        throw error
      })
    )
  } 
  
  catch (errorCallback) {
    return this.then(undefined, errorCallback)
  }

  static resolve(value) {
    // 如果value本身就是promise对象的话直接返回
    if (value instanceof MyPromise) return value
    // 参数是一个thenable对象
    // 将这个对象转为 Promise 对象，然后就立即执行thenable对象的then()方法
    if (typeof value === 'object' && typeof value.then === 'function') return new MyPromise(value.then)
    return new MyPromise(resolve => resolve(value))
  }

  static all(array) {
    let result = []
    let index = 0
    return new MyPromise((resolve, reject) => {
      function addData(key, value) {
        result[key] = value
        index++
        index === array.length && resolve(result)
      }
      for (let i = 0; i < array.length; i++) {
        let current = array[i]
        if (current instanceof MyPromise) {
          // Promise
          current.then(value => addData(i, value), error => reject(error))
        } else {
          // 普通值
          addData(i, array[i])
        }
      }
    })
  }

  // 补充 老师帮忙看下对不对
  // 返回一个新的 Promise 实例，该实例的状态为rejected
  // 方法的参数，会原封不动地作为reject的理由，变成后续方法的参数
  static reject(error) {
    return new MyPromise((resolve, reject) => reject(error))
  }

  static race(array) {
    return new MyPromise((resolve, reject) => {
      for(let i = 0;i <array.length;i++){
        let current = array[i]
        if(current instanceof MyPromise){
          current.then(resolve,reject)
        } else {
          MyPromise.resolve(current).then(resolve,reject)
        }
      }
    })
  }
}

function resolvePromise(x, nextPromise, resolve, reject) {
  if (x instanceof MyPromise) {
    // 避免回调函数返回和当前Promise相等而产生的错误
    if (x === nextPromise) {
      reject(new TypeError('Duplicate MyPromise'))
    } else {
      x.then(resolve, reject)
    }
  } else {
    resolve(x)
  }
}